package com.codi.bus.core.service.organ.impl;

import com.codi.base.exception.BaseAppException;
import com.codi.base.exception.BaseException;
import com.codi.base.exception.ExceptionHandler;
import com.codi.base.util.*;
import com.codi.bus.constant.GlobalConstant;
import com.codi.bus.constant.RuleConstant;
import com.codi.bus.core.dao.*;
import com.codi.bus.core.domain.*;
import com.codi.bus.core.resultModel.AccountOpenResult;
import com.codi.bus.core.resultModel.BaseResult;
import com.codi.bus.core.resultModel.LoginResult;
import com.codi.bus.core.resultModel.OrganDataResult;
import com.codi.bus.core.service.QueryService;
import com.codi.bus.core.service.model.UserModel;
import com.codi.bus.core.service.model.WarningModel;
import com.codi.bus.core.service.organ.OrganAccountService;
import com.codi.bus.core.service.organ.OrganProfileService;
import com.codi.bus.core.service.util.BizUtils;
import com.codi.bus.core.service.util.ObjectCreator;
import com.codi.bus.core.vo.OrganProfileVoNew;
import com.codi.bus.core.vo.UserBankVo;
import com.codi.bus.exception.InterfaceFieldNoFindExcepiton;
import com.codi.bus.exception.SystemDBException;
import com.codi.fcloud.ufx.HsResponseUtil;
import com.codi.fcloud.ufx.HsUtil;
import com.codi.fcloud.ufx.constant.HSOutputParameterNames;
import com.codi.fcloud.ufx.constant.HsConst;
import com.codi.fcloud.ufx.hssale.acco.ClearTradePassword;
import com.codi.message.constant.ErrorConst;
import com.codi.message.constant.ErrorConstant;
import com.codi.message.util.MessageUtil;
import com.codi.trade.dto.FundAcctOpenDto;
import com.codi.trade.service.FundacctDirectOpenAcctService;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @author lvgo
 * @version 1.0
 * @Description: 机构账户相关
 * @date 2018/5/29 9:43
 */
@Slf4j
@Service("organAccountService")
public class OrganAccountServiceImpl implements OrganAccountService {
    @Resource
    private UserDao userDao;
    @Resource(name = "verifyDao")
    private VerifyDao verifyDao;
    @Resource
    private LookupDao lookupDao;
    @Resource(name = "queryService")
    private QueryService queryService;
    @Resource
    private OrganBankDao organBankDao;
    @Resource(name = "organAgentDao")
    private OrganAgentDao organAgentDao;

    @Resource
    private TransactionDao transactionDao;
    @Resource(name = "userSessionDao")
    private UserSessionDao userSessionDao;
    @Resource
    private OrganProfileDao organProfileDao;
    @Resource
    private OrganProfileService organProfileService;
    @Resource(name = "clearTradePassword")
    private ClearTradePassword clearTradePassword;
    @Resource(name = "userSessionHistoryDao")
    private UserSessionHistoryDao userSessionHistoryDao;
    @Resource
    private FundacctDirectOpenAcctService fundacctDirectOpenAcctService;

    /**
     * 通过机构id查询机构信息
     *
     * @param profileId
     * @return
     */
    @Override
    public OrganDataResult queryOrganInfoByProfileId(Long profileId) {
        OrganDataResult organDataResult = new OrganDataResult();
        OrganProfile organProfile = organProfileDao.selectByPrimaryKey(profileId);
        List<OrganBank> organBankList = organBankDao.selectAllListByProfileId(profileId);
        OrganBank organBank = new OrganBank();
        if (organBankList != null && !organBankList.isEmpty()) {
            organBank = organBankList.get(0);
        }
        organDataResult.setOrganProfile(organProfile);
        organDataResult.setOrganBank(organBank);
        return organDataResult;
    }

    /**
     * 更新机构账户（用于机构开户，审核失败，再发起的操作）
     *
     * @param userId
     * @param organProfileVoNew
     * @param userBankVo
     * @return
     * @throws BaseException
     * @throws BaseAppException
     */
    @Override
    public AccountOpenResult reopen(Long userId, String organBankId, OrganProfileVoNew organProfileVoNew,
                                    UserBankVo userBankVo) throws BaseException, BaseAppException {
        AccountOpenResult result = new AccountOpenResult();

        User user = userDao.getEntity(userId);

        OrganProfile organProfile = new OrganProfile();
        org.springframework.beans.BeanUtils.copyProperties(organProfileVoNew, organProfile);


        //只有被拒绝的才可以再次申请开户
        OrganProfile organProfileInDB = organProfileDao.selectByPrimaryKey(organProfileVoNew.getProfileId());
        if (organProfileInDB.getState().intValue() == GlobalConstant.ORGAN_STATE_NOT_PASS) {

        } else {
            log.warn("in valid request");
            ExceptionHandler.publish(ErrorConst.COMMON_INVALID_REQUEST);
        }

        if (!EqualsUtil.equals(organProfileInDB.getProfileId(), organProfile.getProfileId())) {
            log.warn("传递的profileId和数据库中的profileId不一致");
            ExceptionHandler.publish(ErrorConst.COMMON_INVALID_REQUEST);
        }

        // 校验验证执照号唯一性
        boolean exist = organProfileDao.checkBusinessLicenseExist(organProfile.getBusinessLicence(),
            organProfile.getProfileId());
        if (exist) {
            ExceptionHandler.publish(ErrorConst.ORGAN_BIZ_LICENCE_EXIST);
        }

        organProfile.setOrganCode(organProfile.getBusinessLicence());
        organProfile.setTaxRegister(organProfile.getBusinessLicence());

        organProfile.setBusinessLicenceExpireDate(DateUtil.getMaxDate());

        organProfile.setInstreprIdNoExpireDate(DateUtil.getMaxDate());


        // 设置机构银行卡

        UserBank bankEntity = new UserBank();
        org.springframework.beans.BeanUtils.copyProperties(userBankVo, bankEntity);


        bankEntity.setCapitalMode(GlobalConstant.CAPTIAL_MODE_K);
        bankEntity.setUserId(user.getUserId());

        // 获取恒生银行编号
        String bankHSCode = "";
        List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
        for (Lookup lookup : lookups) {
            if (lookup.getComponentValue().equals(bankEntity.getBankCode())) {
                bankHSCode = lookup.getRuleValue();
                break;
            }
        }
        if (StringUtil.isEmpty(bankHSCode)) {
            result.setSuccess(false);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorCode(ErrorConstant.ERROR_NO_BANK_CARD_FIND);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_BANK_CARD_FIND,
                ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, bankEntity.getBankCode()));
            return result;
        }


        // 调用开户接口
        FundAcctOpenDto dto = new FundAcctOpenDto();

        dto.setClient_name(HsUtil.getClientName(organProfile.getCompanyName()));
        dto.setClient_full_name(organProfile.getCompanyName());

        dto.setId_kind_gb(HsConst.ID_KIND_GB_BUSINESS_LICENSE);
        dto.setId_no(organProfile.getBusinessLicence());
        dto.setPassword(MD5.MD5Encode(organProfileVoNew.getTradePassword()));
        dto.setAddress(organProfile.getAddress());
        dto.setMobile_tel(user.getUserMobile());
        dto.setHome_tel(user.getUserMobile());
        dto.setBank_no(bankHSCode);
        dto.setBank_name(bankEntity.getBankBranchName());
        dto.setBank_account(bankEntity.getUserBankNo());
        dto.setBank_account_name(organProfile.getCompanyName());
        dto.setBank_account_name_long(bankEntity.getBankAccountName());
        dto.setCapital_mode(bankEntity.getCapitalMode());
        dto.setRemittance_no("01");
        // 机构
        dto.setCust_type(GlobalConstant.CUST_TYPE_ORGANIZATION);
        dto.setCompany_name(organProfile.getCompanyName());
        dto.setTax_register(organProfile.getTaxRegister());
        dto.setBusiness_range(organProfile.getBusinessRange());
        dto.setInstrepr_name(organProfile.getInstreprName());
        dto.setInstrepr_id_no(organProfile.getInstreprIdNo());
        dto.setInstrepr_id_enddate(DateUtil.format(organProfile.getInstreprIdNoExpireDate(), "yyyyMMdd"));
        dto.setReg_address(organProfile.getAddress());
        dto.setTrade(organProfile.getTrade());
        dto.setCor_property(organProfile.getCorProperty());
        dto.setReg_capital(organProfile.getRegCapital());
        dto.setAddress(organProfile.getAddress());
        dto.setZipcode(organProfile.getPostcode());
        dto.setHome_tel(user.getUserMobile());
        // 经办人
        dto.setContact_name(organProfile.getContactName());
        dto.setContact_tel(organProfile.getContactTel());
        dto.setContact_id_no(organProfile.getContactIdNo());
        // 实际受益人
        dto.setBeneficiary(organProfile.getBeneficiary());
        //实际控制人
        dto.setHolding_name(organProfile.getOwner());
        //银行联号
        dto.setBranchbank(bankEntity.getBranchbank());
        Map<String, Object> map = fundacctDirectOpenAcctService.openAcct(dto);
        if (!HsResponseUtil.isOperationOk(map)) {
            String errorInfo = map.get(HSOutputParameterNames.ERROR_INFO).toString();
            result.setSuccess(false);
            result.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorMessage(errorInfo);
            log.error("open org Account errr info:{}", errorInfo);
        } else {
            // 只有成功时才有交易账号返回
            String externalTradeAccount = map.get(HSOutputParameterNames.TRADE_ACCO).toString();
            bankEntity.setExternalTradeAccount(externalTradeAccount);
            // 返回成功
            result.setSuccess(true);

            // 更新用户信息，法人身份证
            if (StringUtils.isBlank(user.getUserCard())) {
                user.setUserCard(organProfile.getInstreprIdNo());
            }
            userDao.updateUser(user);

            // 添加机构扩展资料
            //添加经办人信息
            OrganAgent agent = organAgentDao.getEntityByMobile(organProfileVoNew.getContactTel().trim());
            if (!Strings.isNullOrEmpty(organProfileVoNew.getContactIdNo()) || !Strings.isNullOrEmpty(organProfileVoNew.getContactName()) || !Strings.isNullOrEmpty(organProfileVoNew.getContactTel())) {
                if (agent == null) {
                    agent = new OrganAgent();
                    agent.setCreateUserId(userId);
                    agent.setCreateTime(new Date());
                    agent.setOrganAgentName(organProfileVoNew.getContactName());
                    agent.setOrganAgentMobile(organProfileVoNew.getContactTel());
                    agent.setOrganAgentIdcard(organProfileVoNew.getContactIdNo());
                    organAgentDao.insertOne(agent);
                }
            }

            // 添加机构扩展资料
            organProfile.setUserId(user.getUserId());
            organProfile.setState(GlobalConstant.ORGAN_STATE_AUDITING);
            organProfile.setExternalClientId(map.get(HSOutputParameterNames.CLIENT_ID).toString());
            organProfileService.addOrUpdateByProfileId(organProfile);


            OrganBank organBank;
            boolean flag = false;
            if (StringUtils.isNotBlank(organBankId)) {
                organBank = organBankDao.selectByPrimaryKey(Long.valueOf(organBankId));
                if (organBank == null) {
                    organBank = new OrganBank();
                } else {
                    flag = true;
                }
            } else {
                organBank = new OrganBank();
            }
            organBank.setUserId(bankEntity.getUserId());
            organBank.setProfileId(organProfile.getProfileId());
            organBank.setUbBankName(bankEntity.getBankName());
            organBank.setUbBankCode(bankEntity.getBankCode());
            // 添加恒生银行编号
            organBank.setUbBankNo(bankHSCode);
            organBank.setAuditStatus(1);
            organBank.setUbOrganBankNo(bankEntity.getUserBankNo());
            organBank.setUbOrganBankOwner(bankEntity.getUserBankOwner());
            organBank.setUbBranchbank(bankEntity.getBranchbank());
            organBank.setUbBankBranchName(bankEntity.getBankBranchName());
            organBank.setUbCapitalMode(bankEntity.getCapitalMode());
            organBank.setExternalTradeAccount(bankEntity.getExternalTradeAccount());
            organBank.setTradePassword(MD5.MD5Encode(organProfileVoNew.getTradePassword()));
            organBank.setCreateTime(new Date());
            organBank.setUserId(userId);
            if (flag) {
                organBankDao.updateByPrimaryKey(organBank);
            } else {
                organBankDao.insertOne(organBank);
            }
            log.info("update user profile info");
        }

        // TODO 需要考虑一种情况，即最后更新交易账号失败，但恒生开户接口已调用成功，需要回滚？
        // 插入交易记录流水
        Transaction transaction = ObjectCreator.createTransaction(map);
        // 不管成功或失败，都插入交易流水
        transactionDao.add(transaction);

        // 设置用户信息
        user = userDao.getEntity(user.getUserId());

        UserModel model = new UserModel();
        model.setIsOrg(true);
        model.setUserId(user.getUserId());
        model.setMobile(user.getUserMobile());
        model.setUserName(user.getUserName());
        model.setProfileId(organProfile.getProfileId());

        result.setUser(model);

        return result;
    }

    /**
     * 机构登录
     *
     * @param mobile
     * @param password
     * @param deviceId
     * @param channelId
     * @param ip
     * @return
     */
    @Override
    public LoginResult organLogin(String mobile, String password, String deviceId, String channelId, String ip) {
        LoginResult result = new LoginResult();
        result.setSuccess(false);

        User user = userDao.getEntityByMobile(mobile.trim());

        if (user == null) {
            log.warn("user[mobile={}] is not exist", mobile);
            ExceptionHandler.publish(ErrorConstant.ERROR_MOBILE_NOT_REG);
        }


        password = MD5.MD5Encode(password);

        if (!password.equals(user.getLoginPassword())) {
            result.setErrorCode(ErrorConstant.ERROR_PASSWORD_WRONG);
            result.setErrorType(GlobalConstant.ERROR_TYPE_BUSINESS);
            result.setErrorMessage(MessageUtil.getErrorMsg(ErrorConstant.ERROR_PASSWORD_WRONG));
            return result;
        }


        // 登录成功，则生产token
        String token = generateToken(user.getUserId(), deviceId, channelId, ip);
        result.setToken(token);
        result.setSuccess(true);

        UserModel model = new UserModel();

        model.setIsOrg(true);
        model.setMobile(user.getUserMobile());
        model.setUserName(user.getUserName());
        model.setUserCard(user.getUserCard());

        boolean isAgent = false;
        List<OrganProfile> organProfiles = organProfileService.queryListByUserId(user.getUserId());
        OrganAgent agent = organAgentDao.getEntityByMobile(user.getUserMobile());
        if (organProfiles == null || organProfiles.isEmpty()) {
            if (agent != null) {
                isAgent = true;
            }
        }
        // 是否是经办人
        model.setIsContact(isAgent);

        //初始化客户信息
        //clientService.initOrganInfo(user.getUserId(), model);
        result.setUser(model);

        //查询警示内容
        List<WarningModel> warningModels = queryService.queryWarnings();
        result.setWarnings(warningModels);

        return result;
    }

    /**
     * 添加机构开户资料
     *
     * @param userId            用户id
     * @param organProfileVoNew 机构资料
     * @param userBankVo        银行卡资料
     * @return
     * @throws BaseAppException
     */
    @Override
    public BaseResult addOrganProfile(Long userId, OrganProfileVoNew organProfileVoNew,
                                      UserBankVo userBankVo) throws BaseAppException {
        Preconditions.checkNotNull(userId);
        Preconditions.checkNotNull(organProfileVoNew);
        Preconditions.checkNotNull(userBankVo);

        OrganProfile organProfile = new OrganProfile();
        org.springframework.beans.BeanUtils.copyProperties(organProfileVoNew, organProfile, "profileId");
        AccountOpenResult result = new AccountOpenResult();

        User user = userDao.getEntity(userId);

        log.info("bank info={}", userBankVo);
        log.info("userId={},mobile={}", user.getUserId(), user.getUserMobile());

        // 校验验证执照号唯一性
        boolean exist = organProfileService.checkBizLicenseExist(organProfile.getBusinessLicence());
        if (exist) {
            ExceptionHandler.publish(ErrorConst.ORGAN_BIZ_LICENCE_EXIST);
        }


        organProfile.setOrganCode(organProfile.getBusinessLicence());
        organProfile.setTaxRegister(organProfile.getBusinessLicence());

        organProfile.setBusinessLicenceExpireDate(DateUtil.getMaxDate());


        organProfile.setInstreprIdNoExpireDate(DateUtil.getMaxDate());


        UserBank bankEntity = new UserBank();
        org.springframework.beans.BeanUtils.copyProperties(userBankVo, bankEntity, "userBankId");
        bankEntity.setCapitalMode(GlobalConstant.CAPTIAL_MODE_K);
        bankEntity.setUserId(user.getUserId());

        OrganProfile profile = null;

        // 获取恒生银行编号
        String bankHSCode = "";
        List<Lookup> lookups = lookupDao.getLookupByType(RuleConstant.RULE_LOOKUP_TYPE_HSBANK);
        for (Lookup lookup : lookups) {
            if (lookup.getComponentValue().equals(bankEntity.getBankCode())) {
                bankHSCode = lookup.getRuleValue();
                break;
            }
        }
        if (StringUtil.isEmpty(bankHSCode)) {
            result.setSuccess(false);
            result.setErrorCode(ErrorConstant.ERROR_NO_BANK_CARD_FIND);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            result.setErrorMessage(MessageUtil.getErrorMessage(ErrorConstant.ERROR_NO_BANK_CARD_FIND,
                ErrorConstant.PLACEHOLDER_FIELD_NO_FIND_FIELD, bankEntity.getBankCode()));
            return result;
        }


        // 组装机构开户参数
        FundAcctOpenDto dto = new FundAcctOpenDto();
        // 机构
        dto.setCust_type(GlobalConstant.CUST_TYPE_ORGANIZATION);
        dto.setBank_no(bankHSCode);
        dto.setRemittance_no("01");
        dto.setHome_tel(user.getUserMobile());
        dto.setTrade(organProfile.getTrade());
        dto.setHome_tel(user.getUserMobile());
        dto.setMobile_tel(user.getUserMobile());
        dto.setAddress(organProfile.getAddress());
        dto.setAddress(organProfile.getAddress());
        dto.setZipcode(organProfile.getPostcode());
        dto.setReg_address(organProfile.getAddress());
        dto.setBank_account(bankEntity.getUserBankNo());
        dto.setId_no(organProfile.getBusinessLicence());
        dto.setCapital_mode(GlobalConstant.CAPTIAL_MODE_K);
        dto.setBank_name(bankEntity.getBankBranchName());
        dto.setReg_capital(organProfile.getRegCapital());
        dto.setCor_property(organProfile.getCorProperty());
        dto.setCompany_name(organProfile.getCompanyName());
        dto.setTax_register(organProfile.getTaxRegister());
        dto.setInstrepr_name(organProfile.getInstreprName());
        dto.setInstrepr_id_no(organProfile.getInstreprIdNo());
        dto.setBusiness_range(organProfile.getBusinessRange());
        dto.setId_kind_gb(HsConst.ID_KIND_GB_BUSINESS_LICENSE);
        dto.setBank_account_name(organProfile.getCompanyName());
        dto.setBank_account_name_long(bankEntity.getBankAccountName());
        dto.setPassword(MD5.MD5Encode(organProfileVoNew.getTradePassword()));
        dto.setClient_name(HsUtil.getClientName(organProfile.getCompanyName()));
        dto.setClient_full_name(HsUtil.getClientFullName(organProfile.getCompanyName()));
        dto.setInstrepr_id_enddate(DateUtil.format(organProfile.getInstreprIdNoExpireDate(), "yyyyMMdd"));
        // 经办人
        dto.setContact_tel(organProfile.getContactTel());
        dto.setContact_name(organProfile.getContactName());
        dto.setContact_id_no(organProfile.getContactIdNo());
        // 实际受益人
        dto.setBeneficiary(organProfile.getBeneficiary());
        // 实际控制人
        dto.setHolding_name(organProfile.getOwner());
        // 银行联号
        dto.setBranchbank(bankEntity.getBranchbank());
        // 调用开户接口
        Map<String, Object> map = fundacctDirectOpenAcctService.openAcct(dto);

        if (!HsResponseUtil.isOperationOk(map)) {
            String errorInfo = map.get(HSOutputParameterNames.ERROR_INFO).toString();
            result.setSuccess(false);
            result.setErrorMessage(errorInfo);
            result.setErrorCode(ErrorConstant.ERROR_HUNDSUNAPI_WRONG);
            result.setErrorType(GlobalConstant.ERROR_TYPE_APPLICATION);
            log.error("open org Account errr info:{}", errorInfo);
        } else {
            // 只有成功时才有交易账号返回
            String externalTradeAccount = map.get(HSOutputParameterNames.TRADE_ACCO).toString();
            // 返回成功
            result.setSuccess(true);
            bankEntity.setExternalTradeAccount(externalTradeAccount);
            bankEntity.setUserBankOwner(organProfile.getCompanyName());
            bankEntity.setUserBankMobile(user.getUserMobile());
            bankEntity.setExternalProtocolNo(null);

            organProfile.setExternalClientId(map.get(HSOutputParameterNames.CLIENT_ID).toString());
            // 更新用户信息，法人身份证
            if (StringUtils.isBlank(user.getUserCard())) {
                user.setUserCard(organProfile.getInstreprIdNo());
            }
            userDao.updateUser(user);

            // 添加机构扩展资料
            //添加经办人信息
            OrganAgent agent = organAgentDao.getEntityByMobile(organProfileVoNew.getContactTel().trim());
            if (!Strings.isNullOrEmpty(organProfileVoNew.getContactIdNo()) || !Strings.isNullOrEmpty(organProfileVoNew.getContactName()) || !Strings.isNullOrEmpty(organProfileVoNew.getContactTel())) {
                if (agent == null) {
                    agent = new OrganAgent();
                    agent.setCreateUserId(userId);
                    agent.setCreateTime(new Date());
                    agent.setOrganAgentName(organProfileVoNew.getContactName());
                    agent.setOrganAgentMobile(organProfileVoNew.getContactTel());
                    agent.setOrganAgentIdcard(organProfileVoNew.getContactIdNo());
                    organAgentDao.insertOne(agent);
                }
            }

            organProfile.setUserId(user.getUserId());
            organProfile.setOrganAgentId(agent.getAgentId());
            organProfile.setState(GlobalConstant.ORGAN_STATE_AUDITING);

            profile = organProfileService.addOrUpdateByProfileId(organProfile);

            log.info("add user profile info");

            OrganBank organBank = new OrganBank();
            organBank.setAuditStatus(1);
            organBank.setUserId(userId);
            // 添加恒生银行编号
            organBank.setUbBankNo(bankHSCode);
            organBank.setCreateTime(new Date());
            organBank.setUserId(bankEntity.getUserId());
            organBank.setProfileId(profile.getProfileId());
            organBank.setUbBankName(bankEntity.getBankName());
            organBank.setUbBankCode(bankEntity.getBankCode());
            organBank.setUbBranchbank(bankEntity.getBranchbank());
            organBank.setUbOrganBankNo(bankEntity.getUserBankNo());
            organBank.setUbCapitalMode(bankEntity.getCapitalMode());
            organBank.setUbOrganBankOwner(bankEntity.getUserBankOwner());
            organBank.setUbBankBranchName(bankEntity.getBankBranchName());
            organBank.setExternalTradeAccount(bankEntity.getExternalTradeAccount());
            organBank.setTradePassword(MD5.MD5Encode(organProfileVoNew.getTradePassword()));
            organBankDao.insertOne(organBank);
        }

        // TODO 需要考虑一种情况，即最后更新交易账号失败，但恒生开户接口已调用成功，需要回滚？
        // 插入交易记录流水
        Transaction transaction = ObjectCreator.createTransaction(map);
        // 不管成功或失败，都插入交易流水
        transactionDao.add(transaction);

        // 设置用户信息
        user = userDao.getEntity(user.getUserId());
        UserModel model = new UserModel();
        model.setIsOrg(true);
        model.setUserId(user.getUserId());
        model.setMobile(user.getUserMobile());
        model.setUserName(user.getUserName());
        if (profile != null) {
            model.setProfileId(profile.getProfileId());
        }
        result.setUser(model);
        return result;
    }


    /**
     * 机构重置交易密码
     *
     * @param userId      用户id
     * @param profileId   机构id
     * @param authCode    验证码
     * @param newTradePwd 新密码
     * @return
     */
    @Override
    public BaseResult resetOrgTradePwd(Long userId, Long profileId, String authCode, String newTradePwd) {
        BaseResult result = new BaseResult(false);

        if (!BizUtils.validateTradePasswd(newTradePwd)) {
            ExceptionHandler.publish(ErrorConstant.ERROR_TRADE_PWD_INVALID);
        }
        User user = userDao.getEntity(userId);

        // 只有审批通过的用户才可以修改密码
        OrganProfile organProfile = organProfileService.getById(profileId);
        if (organProfile == null || StringUtils.isBlank(organProfile.getExternalClientId())) {
            log.warn("用户还未开户");
            ExceptionHandler.publish(ErrorConstant.ERROR_NO_ACCOUNT);
        }

        if (!EqualsUtil.equals(organProfile.getState().intValue(), GlobalConstant.ORGAN_STATE_PASS)) {
            log.warn("该机构账户开户还在审批中（或审批不通过）");
            ExceptionHandler.publish(ErrorConst.ORGAN_OPEN_ACCT_IS_NOT_SUC);
        }

        String mobile = user.getUserMobile();

        if (!checkVerifyCode(mobile, authCode, GlobalConstant.SMS_BIZ_CODE_VERIFY)) {
            ExceptionHandler.publish(ErrorConst.SMS_INVLIAD);
        }
        //删除验证码
        verifyDao.deleteVerifyByMobileAndBizCode(mobile, GlobalConstant.SMS_BIZ_CODE_VERIFY);
        List<OrganBank> organBanks = organBankDao.selectUsableByProfileId(profileId);
        if (organBanks == null || organBanks.isEmpty()) {
            return new BaseResult(false, "未绑定银行卡", GlobalConstant.ERROR_TYPE_BUSINESS);
        }
        OrganBank first = organBanks.get(0);
        log.info("User[mobile={}] begin to reset trade password.", mobile);

        Map<String, Object> res = clearTradePassword.clearTradePasswd(first.getExternalTradeAccount(),
            MD5.MD5Encode(newTradePwd));

        if (!HsResponseUtil.isOperationOk(res)) {
            log.warn("User[mobile={}] reset trade password fail!", mobile);
            return new BaseResult(false, "调用恒生接口失败", GlobalConstant.ERROR_TYPE_APPLICATION);
        }
        log.info("User[mobile={}] reset trade password successfully!", mobile);
        // 更新机构银行卡内容  用于增绑开户校验
        organBanks.forEach(organBank -> {
                organBank.setTradePassword(MD5.MD5Encode(newTradePwd));
                organBankDao.updateByPrimaryKey(organBank);
            }
        );
        result.setSuccess(true);
        return result;
    }


    @Transactional(rollbackFor = BaseException.class)
    String generateToken(Long userId, String deviceId, String channelId, String ip) throws BaseException {
        // 创建用户登录token信息
        Date loginTime = new Date();
        Date expireTime = DateUtils.addDay(loginTime, GlobalConstant.EXPIRED_DAYS);
        String token = UUID.randomUUID().toString().replace("-", "_");
        UserSession session = new UserSession();
        session.setIp(ip);
        session.setToken(token);
        session.setUserId(userId);
        session.setDeviceId(deviceId);
        session.setLoginTime(loginTime);
        session.setChannelId(channelId);
        session.setExpireTime(expireTime);
        // 删除之前先备份，插入历史表
        UserSession backupEntity = userSessionDao.getEntityByUserId(userId);
        if (backupEntity != null) {
            userSessionHistoryDao.addHistory(backupEntity);
            // 先删除之前的 Session
            userSessionDao.deleteByUserId(userId);
        }
        // 插入Session
        userSessionDao.add(session);
        return token;
    }


    @Transactional(readOnly = true)
    public Boolean checkVerifyCode(String mobile, String authCode, String bizCode) throws BaseException {
        if (StringUtil.isEmpty(mobile)) {
            throw new InterfaceFieldNoFindExcepiton("Parameter 'mobile' Is Null!");
        }

        log.info("checkVerifyCode - Mobile:" + mobile);

        try {

            Verify queryEntity = new Verify();
            queryEntity.setMobile(mobile);
            queryEntity.setBizCode(bizCode);
            Verify entity = verifyDao.getEntityByMobileAndBizCode(queryEntity);
            if (entity == null) {
                return false;
            } else {
                if (entity.getExpireDate().before(new Date())) {
                    return false;
                }

                if (!entity.getVerifyCode().equals(authCode)) {
                    return false;
                }
            }

            return true;

        } catch (Exception e) {
            ExceptionUtil.logError(log, "checkVerifyCode - Exception:", e);
            throw new SystemDBException("checkVerifyCode Failure!", e);
        }
    }
}
